/*

        ABluetooth - Processing for Android Bluetooth Library

        Copyright (c) 2012 Marlon J. Manrique
        
        http://www.marlonj.com

        This library is free software; you can redistribute it and/or
        modify it under the terms of the GNU Lesser General Public
        License as published by the Free Software Foundation; either
        version 2.1 of the License, or (at your option) any later version.

        This library is distributed in the hope that it will be useful,
        but WITHOUT ANY WARRANTY; without even the implied warranty of
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
        Lesser General Public License for more details.

        You should have received a copy of the GNU Lesser General
        Public License along with this library; if not, write to the
        Free Software Foundation, Inc., 59 Temple Place, Suite 330,
        Boston, MA  02111-1307  USA

	$Id$

*/

package com.marlonj.processing.abluetooth;

import java.lang.reflect.Method;

import android.bluetooth.BluetoothAdapter; 
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;

import processing.core.PApplet;

/**
 * Processing for Android Bluetooth Library 
 */
public class ABluetooth {

	/**
	 * Parent Applet 
	 */ 
	private PApplet pApplet; 

	/**
	 * The native bluetooth adapter 
	 */ 
	private BluetoothAdapter bluetoothAdapter; 

	/**
	 * Create the library associated with the sketch 
	 *
	 * @param pApplet The parent sketch 
	 */
	public ABluetooth(PApplet pApplet) {
		this.pApplet = pApplet; 

		// Get the default bluetooth adapter if available 
		// if bluetooth is not supported a error must be send 
		// to the sketch and the adapter is null 
		getDefaultAdapter();		
	}	

// <editor-fold defaultstate="collapsed" desc="call events">

	/**
	 * Call the method from the sketch
	 * 
	 * @param methodName Name of the method
	 * @param params Parameters to send 
	 */ 
	public void callMethod(String methodName, Object[] params) {

		// Get the methods of the class 
		Method[] methods = pApplet.getClass().getMethods();

		// The methods to call 
		Method eventMethod = null; 

		// Search by name the method to call 
		for(int i=0; i<methods.length; i++) {
			if(methodName.equals(methods[i].getName())) {
				eventMethod = methods[i];
			}
		}		

		try {
			// Call the method if was found 
			if(eventMethod != null) {
				eventMethod.invoke(pApplet,params);
			}
		} catch(Exception e) {
			e.printStackTrace();
		}
	}

// </editor-fold>


	/**
	 * Returns the default adapter of the device
	 */ 
	private void getDefaultAdapter() {
		// Get the default adapter in the same thread that the UI to avoid 
		// problens with the Handler 
		pApplet.runOnUiThread(new Runnable() {
			public void run() { 
				try {
					// Get the default adapter 
					// Can be null if not available 
					bluetoothAdapter 
						= BluetoothAdapter.getDefaultAdapter();
				} catch(Exception e) {
					// TODO : send the error message to the sketch 
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Returns the name of the device 
	 * 
	 * @return The name given to the device in the bluetooth settings 
	 */ 
	public String deviceName() {
		// Name of the device 
		String deviceName = null; 

		// Get the device name
		if(bluetoothAdapter != null) {
			deviceName = bluetoothAdapter.getName();
		} 

		// If the name is still null the bluetooth is not available 
		if(deviceName == null) {
			deviceName = "Bluetooth Not Available";
		}
		
		// Return the name of the device 
		return deviceName;
	}

	/**
	 * Returns the bluetooth address of the device 
	 * 
	 * @return The address of the bluetooth adapter 
	 */ 
	public String deviceAddress() {
		// The device Address 
		String deviceAddress = null; 

		// Get the bluetooth address 
		if(bluetoothAdapter != null) {
			deviceAddress = bluetoothAdapter.getAddress();			
		}

		// If the address is still null the bluetooth is not available  
		if(deviceAddress == null) {
			deviceAddress = "Bluetooth Not Available";
		}
		
		// The device address 
		return deviceAddress;
	}

	/**
	 * Check if the bluetooths is enabled 
	 * 
	 * @return true is the bluetooth is enable 
	 */
	public boolean isEnabled() {
		// The bluetooth is available 
		boolean available = false; 

		// Check if the adapter is not null and is enable 
		if(bluetoothAdapter != null) {
			available = bluetoothAdapter.isEnabled();
		}

		// Return if the service is enable 
		return available;
	}

// <editor-fold defaultstate="collapsed" desc="discover">

	/**
	 * Discover other bluetooth devices 
	 */ 
	public void discover() {
		// Start the discover of the devices 
		// this method returns immediately and the BroadcastReceiver is call 
		// when a device is found 
		if(bluetoothAdapter != null) {
			// Register the broadcast receiver and begin discover devices  
			registerBroadcastReceiver();
			bluetoothAdapter.startDiscovery();
		}
	}

	/**
	 * Receive intents from discover devices 
	 */
	private ABroadcastReceiver broadcastReceiver; 

	/**
	 * Register the broadcast receiver to retrive information from the 
	 * discovered devices 
	 */
	private void registerBroadcastReceiver() {
		// If the broadcastReceiver is not created yet 
		// Create one to retrive the information of the device found 
		if(broadcastReceiver == null) {
			broadcastReceiver = new ABroadcastReceiver(this);

			// Create the filter to listen when a device is found 
			// and register the broadcastReceiver to be call 
			IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
			filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);			
			pApplet.registerReceiver(broadcastReceiver, filter);
		}
	}

	/**
	 * The discover service found a new device 
	 * 
	 * @param device The device discovered 
	 */
	void deviceDiscovered(ABluetoothDevice device) {
		// Call the method in the sketch to show the device 
		callMethod("deviceDiscovered", new Object[] { device });
	}

	/**
	 * The discover service end 
	 */ 
	void discoveryEnded() {
		// Call the method in the sketch 
		callMethod("discoveryEnded", new Object[] {});
	}

// </editor-fold>
}
